﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using G.Model;
using GameRuntimeLibrary.Model.Runtime;
using G.Runtime;

namespace G.Runtime
{
    public class ElementEventArgs
    {
        public GameElement element;
        public bool handled;
    }
        
    public class GameElements : 
        KeyedCollection<GameLocation, GameElement>,
        HasGameSpace
    {
        
        public delegate void ElementPositionChangedHandler(GameLocation location);
        public delegate void ElementHandler(GameElement subject);
        public delegate void PlayerChangedHandler(GameElement element);
        public delegate void ElementEventHandler(ElementEventArgs args);

        public event PlayerChangedHandler PlayerChangingEvent;
        public event PlayerChangedHandler PlayerChangedEvent;
        public event ElementHandler PropertyChangedEvent;
        public event ElementPositionChangedHandler ElementPositionChangedEvent;
        public event ElementHandler ElementMovedEvent;
        public event ElementHandler ElementAddedEvent;
        public event ElementHandler ElementRemovedEvent;
        public event ElementEventHandler Click;

        private readonly GameSpace _Game;
        private readonly GameElementDefs _GameElementDefs;
        private readonly GameElementActions _Actions;

        public GameElements(GameElementDefs defs, GameSpace game)
        {
            _Game = game;
            _GameElementDefs = defs;
            _Actions = new GameElementActions();
            ElementMovedEvent += this.OnElementMoved;
        }

        protected override void InsertItem(int index, GameElement item)
        {
            if (item.Game != _Game)
            {
                throw new ArgumentException("Wrong playspace");
            }
            base.InsertItem(index, item);
            _Game.Players.Sync();
            if (ElementAddedEvent != null)
            {
                ElementAddedEvent(item);
            }
        }
        
        protected override void RemoveItem(int index)
        {
            GameElement element = base.Items[index];
            base.RemoveItem(index);
            FireElementPositionChanged(element.Location);
            if (ElementRemovedEvent != null)
            {
                ElementRemovedEvent(element);
            }
        }
        
        public GameSpace Game
        {
            get { return _Game; }
        }
        
        public GameElementActions Actions
        {
            get { return _Actions; }
        }

        public ICollection<string> PlayerNames
        {
            get
            {
                List<string> list = new List<string>();
                if (base.Dictionary == null)
                {
                    return list;
                }
                foreach (GameElement e in base.Dictionary.Values)
                {
                    if (!list.Contains(e.Player))
                    {
                        list.Add(e.Player);
                    }
                }
                return list;
            }
        }
        
        public GameElement Get(int x, int y)
        {
            return this[new GameLocation(x,y)];
        }

        public void SetPosition(GameElement e, GameLocation location)
        {
            GameLocation save = e.Location;
            Remove(e);
            e.SetLocation(location);
            
            if (this.Contains(location)) 
            {
                Remove(location);
            }
            Add(e);
            FireElementPositionChanged(save);
            FireElementPositionChanged(location);
            e.FireElementMoved();
            e.FireLocationChanged(save);
        }

        internal void FirePlayerChanged(GameElement element)
        {
            if (PlayerChangedEvent != null)
            {
                PlayerChangedEvent(element);
            }
        }

        internal void FirePlayerChanging(GameElement element)
        {
            if (PlayerChangingEvent != null)
            {
                PlayerChangingEvent(element);
            }
        }
        
        internal void FireElementPositionChanged(GameLocation location)
        {
            if (ElementPositionChangedEvent != null)
            {
                ElementPositionChangedEvent(location);
            }
        }

        internal void FireElementMoved(GameElement element)
        {
            if (ElementMovedEvent != null)
            {
                ElementMovedEvent(element);
            }
        }

        internal void FireElementPropertyChanged(GameElement element)
        {
            if (PropertyChangedEvent != null)
            {
                PropertyChangedEvent(element);
            }
        }

        public ElementEventArgs RaiseClickEvent(GameElement element)
        {
            ElementEventArgs args = new ElementEventArgs();
            args.element = element;
            if (Click != null)
            {
                Click(args);
            }
            return args;
        }
        
        protected override GameLocation GetKeyForItem(GameElement item)
        {
            return item.Location;
        }

        private void OnElementMoved(GameElement subject)
        {
            //IntGameValue e = (IntGameValue)
            //    _Game.Globals.Values[Constants.MOVES];

            //e.Value++;
        }

    }
}
